package FlowGram.Application.IDEWindow.FileHost;

import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Graphics;
import java.awt.event.ComponentEvent;
import java.awt.event.MouseEvent;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;

import FlowGram.Application.Application;
import FlowGram.Application.IDEWindow.MainWindow;
import FlowGram.Application.Parser.FinchParser;
import FlowGram.Application.Parser.FinchParserException;
import FlowGram.Application.Parser.FinchProgramFlow;

import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class FileHost extends JPanel {
	
	
	private JTabbedPane MainTabbedPane;
	private CodeFile currentCodeFile;
	private ArrayList<CodeFile> openFiles = new ArrayList<CodeFile>();
	private boolean editable = false;
	

	public FileHost(){
		
		MainTabbedPane = new JTabbedPane();
		MainTabbedPane.setSize(this.getSize());
		MainTabbedPane.addChangeListener(new ChangeListener(){
			public void stateChanged(ChangeEvent evt){
				int selectedTabIndex = MainTabbedPane.getSelectedIndex();
				if(selectedTabIndex>=0){
					setCurrentFile(selectedTabIndex);
				}
			}
		});
		MainTabbedPane.setTabLayoutPolicy(JTabbedPane.SCROLL_TAB_LAYOUT);
		
		this.setBorder(new EmptyBorder(10, 10, 10, 10) );
		this.add(MainTabbedPane);
	}
	
	public void newFile() throws FinchParserException{

		//create a new codeFile instance for the file to be opened
		CodeFile currentCodeFile = new CodeFile("Untitled.txt",null,false,null);
		currentCodeFile.setProgramFlow(new FinchProgramFlow());
		//set the currentCodeFile to the new codeFile created
		this.currentCodeFile = currentCodeFile;
		this.currentCodeFile.setFileTabbedPane(this.setUpPane());
		this.currentCodeFile.setDirty(true);
		//add the codeFile to a list of open Files
		
		this.openFiles.add(this.currentCodeFile);
		MainTabbedPane.addTab(this.currentCodeFile.getName(),this.currentCodeFile.getFileTabbedPane());
		
		MainTabbedPane.setSelectedComponent(this.currentCodeFile.getFileTabbedPane());
		
		if(editable){
			isEditable();
		}
		else{
			isNotEditable();
		}
	
	}
	
	public String getFileString(File currentFile) throws IOException{
		String line;
	    BufferedReader reader = new BufferedReader(new FileReader(currentFile));
	    StringBuilder codeString = new StringBuilder();
	    while ((line = reader.readLine()) != null)
	    {
	      codeString.append(line);
	      codeString.append("\n");
	    }
	    reader.close();
	    return codeString.toString();
	}
	
	public JTabbedPane setUpPane(){
		JTabbedPane fileTabbedPane;
		CodeEditor codeEditor = new CodeEditor();
		FlowEditor flowEditor = new FlowEditor();
		
		
		//Add the contents of the file to be open to the code Editor
		codeEditor.setUpCodeEditor(this.currentCodeFile.getProgramFlow());
		flowEditor.setUpFlowEditor(this.currentCodeFile.getProgramFlow());
		
		fileTabbedPane = new JTabbedPane();
		fileTabbedPane.setSize(MainTabbedPane.getSize());
		codeEditor.setSize(fileTabbedPane.getSize());
		flowEditor.setSize(fileTabbedPane.getSize());
		fileTabbedPane.addTab( "Code Editor", codeEditor );
		fileTabbedPane.addTab( "Flow Editor", flowEditor );
		this.add( fileTabbedPane, BorderLayout.CENTER );
		fileTabbedPane.setTabPlacement(JTabbedPane.BOTTOM);
		codeEditor.getCodeEditorPane().getDocument().addDocumentListener(new MyDocumentListener(this));
		return fileTabbedPane;
	}
	
	
	public void openFile(String filePath) throws IOException, FinchParserException{
		for(int i=0;i<openFiles.size();i++){
			if(openFiles.get(i).getPath()!=null){
				if(openFiles.get(i).getPath().equals(filePath)){
					this.currentCodeFile = openFiles.get(i);
					MainTabbedPane.setSelectedComponent(this.currentCodeFile.getFileTabbedPane());
					return;
				}
			}
		}
		//a new file instance of the file to be opened
		File currentFile = new File(filePath);
		//a new parser instance
		FinchParser parser = new FinchParser();
		//codeString to get a string
		String codeString = getFileString(currentFile);
		//set up the tabbing pane for the file to be opened
		//create a new codeFile instance for the file to be opened
		CodeFile currentCodeFile = new CodeFile(currentFile.getName(),filePath,false,parser.Parse(codeString));
		//set the currentCodeFile to the new codeFile created
		this.currentCodeFile = currentCodeFile;
		this.currentCodeFile.setDirty(false);
		this.currentCodeFile.setFileTabbedPane(this.setUpPane());
		//add the codeFile to a list of open Files
		
		this.openFiles.add(this.currentCodeFile);
		MainTabbedPane.addTab(this.currentCodeFile.getName(),this.currentCodeFile.getFileTabbedPane());
		
		MainTabbedPane.setSelectedComponent(this.currentCodeFile.getFileTabbedPane());
		if(editable){
			isEditable();
		}
		else{
			isNotEditable();
		}
	}
	
	public void saveFile() throws IOException{
		String[] statements;
		int currentStatementCount = 0;
		File codeFile = null;

		String codeString = currentCodeFile.getProgramFlow().toCode();
		
		statements = codeString.split("\r\n");
		if(currentCodeFile.getPath()!=null){
			codeFile = new File(currentCodeFile.getPath());
		}
		else{
			JFileChooser chooser = new JFileChooser();
			chooser.setSelectedFile(new File(Application.getInstance().getCurrentProjectPath()));
            int returnVal = chooser.showSaveDialog(null);
            if(returnVal == JFileChooser.APPROVE_OPTION) {
            	try {
            		JOptionPane.showMessageDialog(null, "Saving code file:\n"+chooser.getSelectedFile().getPath());
					this.saveFileAs(chooser.getSelectedFile().getPath());
					Application.getInstance().getMainWindow().refreshFileManager();
				} catch (IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
            }
		}
		
		FileWriter codeFileWriter = new FileWriter(codeFile, false);//true to append and false to overwrite
		while(currentStatementCount < statements.length){
			String currentStatement = statements[currentStatementCount].trim();
			codeFileWriter.write(currentStatement+"\n");
			currentStatementCount++;
		}
			codeFileWriter.close();
			this.currentCodeFile.setDirty(false);
	}
	
	public void saveFileAs(String newFilePath) throws IOException{
		int indexOfOldComponent = MainTabbedPane.getSelectedIndex();
		String[] statements;
		int currentStatementCount = 0;
		String codeString = currentCodeFile.getProgramFlow().toCode();
		int result;
		statements = codeString.split("\r\n");
		File codeFile = new File(newFilePath);
		
		boolean success = codeFile.createNewFile();
	    if (!success) {
	    	// File already exists
	    	result = JOptionPane.showConfirmDialog(this, "A file with this name already exists. Would you like to overwrite it?");
	    	if(JOptionPane.NO_OPTION ==result){
	    		JFileChooser chooser = new JFileChooser();
	            int returnVal = chooser.showSaveDialog(null);
	            if(returnVal == JFileChooser.APPROVE_OPTION) {
	            	try {
	            		JOptionPane.showMessageDialog(null, "Saving code file:\n"+chooser.getSelectedFile().getPath());
						this.saveFileAs(chooser.getSelectedFile().getPath());
						Application.getInstance().getMainWindow().refreshFileManager();
					} catch (IOException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
	            }
	    	}
	    	if(JOptionPane.CANCEL_OPTION ==result){
	    		return;
	    	}
	        
	    } else {
	    	JOptionPane.showMessageDialog(this, "Your File was saved successfully!");
	    	this.currentCodeFile.setDirty(false);
	    }
		
		FileWriter codeFileWriter = new FileWriter(codeFile, false);//true to append and false to overwrite
		while(currentStatementCount < statements.length){
			String currentStatement = statements[currentStatementCount].trim();
			codeFileWriter.write(currentStatement+"\n");
			currentStatementCount++;
		}
			codeFileWriter.close();
			currentCodeFile.setName(codeFile.getName());
			currentCodeFile.setPath(codeFile.getPath());
			MainTabbedPane.setTitleAt(indexOfOldComponent, currentCodeFile.getName());
	}
	public void closeFile() throws IOException{
		if(this.currentCodeFile.isDirty()){
			int result = JOptionPane.showConfirmDialog(this,  this.currentCodeFile.getName()+ " has been changed. Do you want to save it?");
			if(JOptionPane.YES_OPTION==result){
				saveFile();
			}else if(JOptionPane.CANCEL_OPTION == result){
				return;
			}
		}
		setUpNewFile();
	}
	
	public void setUpNewFile(){
		
		int selectedTabIndex = MainTabbedPane.getSelectedIndex();
		if(selectedTabIndex>=0){
			openFiles.remove(this.currentCodeFile);
			MainTabbedPane.remove(selectedTabIndex);
			
		}
	}
	
	public void setCurrentFile(int selectedTabIndex){
		CodeFile currentFile;
		for(int i=0; i<openFiles.size();i++){
			currentFile = openFiles.get(i);
			if(selectedTabIndex>=0){
				if(currentFile.getName().equals(MainTabbedPane.getTitleAt(selectedTabIndex))){
					this.currentCodeFile = currentFile;
				}
			}
		}
	}
	
	public void setCurrentPane(CodeFile currentCodeFile){
		for(int i =0; i<openFiles.size();i++){
			if(currentCodeFile.getName().equals(MainTabbedPane.getTitleAt(i))){
				MainTabbedPane.setSelectedIndex(i);
			}
		}
	}
	
	public void saveAll() throws IOException{
		for(int i =0;i<openFiles.size();i++){
			if(openFiles.get(i).isDirty()){
				System.out.println("hello");
				this.currentCodeFile = openFiles.get(i);
				setCurrentPane(this.currentCodeFile);
				saveFile();
			}
			setCurrentFile(MainTabbedPane.getSelectedIndex());
		}
	}
	public void closeAll() throws IOException{
		while(!openFiles.isEmpty()){
			closeFile();
		}
		
	}
	
	public boolean getEditable(){
		return this.editable;
	}
	
	public void setEditable(boolean newEditable){
		this.editable = newEditable;
	}
	
	public CodeFile getCurrentCodeFile(){
		return this.currentCodeFile;
	}
	
	public void setCurrentCodeFile(CodeFile newCodeFile){
		this.currentCodeFile = newCodeFile;
	}
	public void isEditable(){
		for(int i=0; i<openFiles.size();i++){
			CodeFile currentFile = openFiles.get(i);
			CodeEditor currentFileEditor = (CodeEditor)currentFile.getFileTabbedPane().getComponentAt(0);
			currentFileEditor.getCodeEditorPane().setEditable(true);
		}
		this.editable=true;
	}
	
	public void isNotEditable(){
		for(int i=0; i<openFiles.size();i++){
			CodeFile currentFile = openFiles.get(i);
			CodeEditor currentFileEditor = (CodeEditor)currentFile.getFileTabbedPane().getComponentAt(0);
			currentFileEditor.getCodeEditorPane().setEditable(false);
			this.editable=false;
		}
	}
	
	public ArrayList<CodeFile> getOpenFiles(){
		return this.openFiles;
	}
	
	public void componentResized(ComponentEvent e) {
		this.MainTabbedPane.setSize(this.getSize());
		this.validate();
	}
	
	
}
